package com.jvyou.mybatis.executor.resultset;

import com.jvyou.mybatis.exception.JvyouMybatisException;
import com.jvyou.mybatis.mapping.MappedStatement;
import com.jvyou.mybatis.session.Configuration;
import com.jvyou.mybatis.type.TypeHandler;
import com.jvyou.mybatis.utils.clazz.TypeUtils;

import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 橘柚
 * @version 1.0-SNAPSHOT
 * @Date 2024/5/14 14:05
 * @Description 默认结果集处理器
 */
public class DefaultResultSetHandler implements ResultSetHandler {

    private final Configuration configuration;

    public DefaultResultSetHandler(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <T> List<T> handleResultSets(MappedStatement ms, PreparedStatement ps) {
        Class<?> returnType = ms.getResultType();
        ResultSet resultSet;
        try {
            resultSet = ps.getResultSet();
        } catch (SQLException e) {
            throw new JvyouMybatisException("Mapping a ResultSet to a query result failed with nested exceptions:\n" + e);
        }
        List<T> result = new ArrayList<>();
        try {
            // 判断 returnType 是否为 基本数据类型
            if (TypeUtils.isBaseType(returnType)) {
                handlePrimitiveType(returnType, resultSet, result);
            } else {
                handleObjectType(returnType, resultSet, result);
            }
            resultSet.close();
        } catch (SQLException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    private <T> void handlePrimitiveType(Class<?> returnType, ResultSet resultSet, List<T> result) throws SQLException {
        TypeHandler<Object> typeHandler = configuration.getTypeHandler(returnType);
        if (typeHandler == null) {
            throw new JvyouMybatisException("TypeHandler not found for type " + returnType.getName());
        }
        if (resultSet.next()) {
            Object value = typeHandler.getResult(resultSet, 1);
            result.add((T) value);
        }
    }


    @SuppressWarnings("unchecked")
    private <T> void handleObjectType(Class<?> returnType, ResultSet resultSet, List<T> result) throws SQLException, InstantiationException, IllegalAccessException {
        // 获取表的元数据信息
        TableMetaData tableMetaData = configuration.getTableMetaData(returnType);
        Map<String, Field> fieldMap = tableMetaData.getFieldMap();

        ResultSetMetaData metaData = resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();
        String columnName;

        while (resultSet.next()) {

            Object obj = returnType.newInstance();

            for (int i = 1; i <= columnCount; i++) {
                columnName = metaData.getColumnName(i);
                if (!fieldMap.containsKey(columnName)) {
                    continue;
                }
                Field field = fieldMap.get(columnName);
                field.setAccessible(true);
                TypeHandler<?> typeHandler = configuration.getTypeHandler(field.getType());
                Object value = typeHandler.getResult(resultSet, columnName);
                field.set(obj, value);
            }
            result.add((T) obj);
        }
    }
}
